import { Inject, Provide } from "@midwayjs/core";
import { InjectEntityModel } from "@midwayjs/typeorm";
import { Repository } from "typeorm";
import { Utils } from "../utils";
import { BblRecord } from "../entity/record.entity";
import { AttachService } from "./att.service";
import {
  RecordCreateDto,
  RecordDto,
  RecordPageQueryDto,
  RecordUpdateDto
} from "../dto/record.dto";
import { BblAttach } from "../entity/attach.entity";
import { UploadFileInfo } from "@midwayjs/upload";
import * as AdmZip from "adm-zip";
import * as path from "path";

import * as xlsx from "xlsx";
import * as fs from "fs";

@Provide()
export class RecordService {
  @Inject()
  utils: Utils;

  @Inject()
  attService: AttachService;

  /**
   * 附件驱动模型
   */
  @InjectEntityModel(BblRecord)
  model: Repository<BblRecord>;

  async get_origin_by_code(recordCode: string) {
    const builder = this.model
      .createQueryBuilder("record")
      .leftJoinAndSelect("record.recordMainImgs", "recordMainImgs")
      .where("record.recordCode = :recordCode", { recordCode });
    return await builder.getOne();
  }

  async get_origin_by_id(recordId: string) {
    const builder = this.model
      .createQueryBuilder("record")
      .leftJoinAndSelect("record.recordMainImgs", "recordMainImgs")
      .where("record.recordId = :recordId", { recordId });

    return await builder.getOne();
  }

  async add_record(dto: RecordCreateDto) {
    let record = RecordCreateDto.toRecord(dto);

    const old_record = await this.model.find({
      where: {
        recordCode: record.recordCode
      }
    });

    console.log(old_record);
    // TODO 检查old_record是否存在，存在不允许继续创建

    await this.model.save(record);
    record = await this.get_origin_by_id(record.recordId);
    await this.attService.tmp_to_uploads(record.recordMainImgs);
    return this.utils.service.success(record);
  }

  async update_record(recordId: string, dto: RecordUpdateDto) {
    let record = await this.get_origin_by_id(recordId);
    if (!record) {
      return this.utils.service.fail({
        message: "球杆档案不存在"
      });
    }

    // 原有图片id不在dto中的，进入删除列表
    const rfiles = [];
    record.recordMainImgs.forEach((d) => {
      if (!dto.recordMainImgIds.includes(d.attId)) {
        rfiles.push(d);
      }
    });
    await this.attService.remove(rfiles);

    record.recordCode = dto.recordCode;
    record.recordBrand = dto.recordBrand;
    record.recordWeight = dto.recordWeight;
    record.recordLength = dto.recordLength;
    record.recordCenter = dto.recordCenter;
    record.recordTopDiam = dto.recordTopDiam;
    record.recordTailDiam = dto.recordTailDiam;
    record.recordMainImgs = dto.recordMainImgIds.map((d) => {
      const att = new BblAttach();
      att.attId = d;
      return att;
    });
    record.recordText = dto.recordText;

    // 保存
    await this.model.save(record);

    // 查询更新后的数据
    record = await this.get_origin_by_id(record.recordId);
    // 将临时文件夹中的图片移动到正式文件夹中
    await this.attService.tmp_to_uploads(record.recordMainImgs);

    return this.utils.service.success(record);
  }

  async delete_record(recordId: string) {
    const record = await this.get_origin_by_id(recordId);
    if (!record) {
      return this.utils.service.fail({
        message: "球杆档案不存在"
      });
    }
    await this.attService.remove(record.recordMainImgs);
    await this.model.remove(record);
    return this.utils.service.success(recordId);
  }

  async get_record_page_list(dto: RecordPageQueryDto) {
    const builder = this.model
      .createQueryBuilder("record")
      .leftJoinAndSelect("record.recordMainImgs", "recordMainImgs")
      .where("1=1")
      .orderBy("record.createAt", "DESC");

    if (dto.recordCode) {
      builder.andWhere("record.recordCode like :recordCode", {
        recordCode: `%${dto.recordCode}%`
      });
    }

    if (dto.recordBrand) {
      builder.andWhere("record.recordBrand like :recordBrand", {
        recordBrand: `%${dto.recordBrand}%`
      });
    }

    const total = await builder.getCount();

    builder.skip((dto.current - 1) * dto.pageSize);
    builder.take(dto.pageSize);

    const list = await builder.getMany();

    const records = list.map((d) => RecordDto.from(d));

    return this.utils.service.success({
      total,
      records,
      current: Number(dto.current),
      pageSize: Number(dto.pageSize)
    });
  }

  async check_record_exist(recordCode: string) {
    const record = await this.get_origin_by_code(recordCode);
    if (!record) {
      return this.utils.service.fail(null, "查询的球杆不存在");
    } else {
      const dto = RecordDto.from(record);
      return this.utils.service.success(dto);
    }
  }

  async batch_upload_record_new(file: UploadFileInfo<any>) {
    const unzip = new AdmZip(file.data);
    const dir = path.resolve(process.cwd(), "tmp", this.utils.uuid());
    unzip.extractAllTo(dir, true);

    const workbook = xlsx.readFile(path.resolve(dir, "data.xlsx"));
    const json = xlsx.utils.sheet_to_json(
      workbook.Sheets[workbook.SheetNames[0]]
    );
    const records = json.map((d) => {
      const record = new BblRecord();
      record.recordCode = d["球杆编号"];
      record.recordBrand = d["球杆品牌"];
      record.recordWeight = d["球杆重量(oz)"];
      record.recordLength = d["球杆长度(cm)"];
      record.recordCenter = d["球杆重心(cm)"];
      record.recordTopDiam = d["杆头直径(mm)"];
      record.recordTailDiam = d["握把直径(mm)"];
      record.recordText = d["描述(可不填)"] || "";
      record.recordMainImgs = [];
      record.recordId = this.utils.uuid();
      return record;
    });

    const files = fs.readdirSync(dir);

    // 过滤文件夹，并且文件夹的名字要和excel中的编码相同
    const record_dir = files.filter((d) => {
      const stat = fs.statSync(path.resolve(dir, d));
      if (stat.isDirectory()) {
        const index = records.findIndex((x) => x.recordCode === d);
        return index >= 0;
      } else {
        return false;
      }
    });
    const allatts: BblAttach[] = [];
    record_dir.forEach((d) => {
      const record = records.find((x) => x.recordCode === d);
      if (record) {
        const src = path.resolve(dir, d);
        const ts = fs.readdirSync(src);

        // 只处理 png、jpg、webp文件
        const imgs = ts.filter((d) => {
          const png = d.indexOf(".png") > 0;
          const jpg = d.indexOf(".jpg") > 0 || d.indexOf(".jpeg") > 0;
          const webp = d.indexOf(".webp") > 0;
          return png || jpg || webp;
        });

        const atts: BblAttach[] = [];

        for (let i = 0; i < imgs.length; i++) {
          const oldPath = path.resolve(src, imgs[i]);
          const filename = path.basename(oldPath);
          const ext = filename.split(".")[1];
          const newPath = path.resolve(src, this.utils.uuid() + "." + ext);

          fs.renameSync(oldPath, newPath);

          const attach = new BblAttach();
          attach.attName = filename;
          attach.attExt = ext;
          attach.attState = "0";
          attach.attPath = "";
          attach.attTempPath = newPath;
          attach.attMimeType = "";
          attach.attId = this.utils.uuid();

          atts.push(attach);
          record.recordMainImgs.push(attach);
        }

        allatts.push(...atts);
      }
    });

    await this.attService.save(allatts);
    await this.attService.tmp_to_uploads(allatts);

    await this.model.save(records);

    const list = records.map((d) => RecordDto.from(d));

    return this.utils.service.success(list);
  }

  async batch_upload_record(file: UploadFileInfo<any>) {
    const unzip = new AdmZip(file.data);
    const dir = path.resolve(process.cwd(), "tmp", this.utils.uuid());
    unzip.extractAllTo(dir, true);

    const workbook = xlsx.readFile(path.resolve(dir, "data.xlsx"));
    const json = xlsx.utils.sheet_to_json(
      workbook.Sheets[workbook.SheetNames[0]]
    );
    const records = json.map((d) => {
      const record = new BblRecord();
      record.recordCode = d["球杆编号"];
      record.recordBrand = d["球杆品牌"];
      record.recordWeight = d["球杆重量(oz)"];
      record.recordLength = d["球杆长度(cm)"];
      record.recordCenter = d["球杆重心(cm)"];
      record.recordTopDiam = d["杆头直径(mm)"];
      record.recordTailDiam = d["握把直径(mm)"];
      record.recordText = d["描述(可不填)"] || "";
      record.recordMainImgs = [];
      record.recordId = this.utils.uuid();
      return record;
    });

    const files = fs.readdirSync(dir);

    const imgs = files.filter((d) => {
      const notexcel = d.indexOf("xlsx") < 0;
      const png = d.indexOf(".png") > 0;
      const jpg = d.indexOf(".jpg") > 0;
      const webp = d.indexOf(".webp") > 0;
      return notexcel && (png || jpg || webp);
    });

    const atts: BblAttach[] = [];

    for (let i = 0; i < imgs.length; i++) {
      const prefix = imgs[i].split(".")[0];
      const rinfo = prefix.split("_");
      if (rinfo.length !== 2) continue;
      const [recordCode] = rinfo;

      const oldPath = path.resolve(dir, imgs[i]);
      const filename = path.basename(oldPath);
      const ext = filename.split(".")[1];
      const newPath = path.resolve(dir, this.utils.uuid() + "." + ext);

      fs.renameSync(oldPath, newPath);

      const attach = new BblAttach();
      attach.attName = filename;
      attach.attExt = ext;
      attach.attState = "0";
      attach.attPath = "";
      attach.attTempPath = newPath;
      attach.attMimeType = "";
      attach.attId = this.utils.uuid();

      const record = records.find((d) => d.recordCode === recordCode);
      if (record) {
        atts.push(attach);
        record.recordMainImgs.push(attach);
      }
    }

    await this.attService.save(atts);
    await this.attService.tmp_to_uploads(atts);

    await this.model.save(records);

    const list = records.map((d) => RecordDto.from(d));

    return this.utils.service.success(list);
  }
}
